# -*- coding: utf-8 -*-
"""
-------------------------------------------------
Project Name: luffcity study project
File Name: main.py
Author: kij
Create Date: 2021/2/27
-------------------------------------------------
"""
import os, hashlib, json, socket, configparser, subprocess
from conf import setting


class FTPServer(object):
	"""
	处理所有客户端与服务器端的交互
	"""
	STATUS_CODE = {
		200: 'passed authentication',
		201: 'wrong username or password',
		300: 'file does not exits',
		301: 'File exist , and this msg include the file size- !',
		302: 'Folder exist , and this msg include the file size- !',
	}

	MSG_SIZE = 1024

	def __init__(self, management_instance):
		self.management_instance = management_instance
		self.user_obj = None
		self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
		self.sock.bind((setting.HOST, setting.PORT))
		self.sock.listen(setting.MAX_SOCKET_LISTEN)
		self.accounts = self.load_accounts()

	def run_forever(self):
		"""
		启动socket_server
		:return:
		"""
		print('start ftp server on %s:%s'.center(50, "-") % (setting.HOST, setting.PORT))

		while True:
			self.request, self.addr = self.sock.accept()
			print('get a new connection from %s....' % (self.addr,))
			self.handle()

	def handle(self):
		while True:
			raw_data = self.request.recv(self.MSG_SIZE)
			if not raw_data:
				print("connection %s is lost" % self.addr)
				del self.request, self.addr
				break
			data = json.loads(raw_data.decode('utf-8'))
			action_type = data.get('action_type')
			print('----->', action_type)
			if action_type:
				if hasattr(self, "_%s" % action_type):
					func = getattr(self, "_%s" % action_type)
					func(data)
			else:
				print("缺少参数")

	def authenticate(self, user_name, user_password):
		"""验证用户名和密码"""
		if user_name in self.accounts:
			_password = self.accounts[user_name]['password']
			md5_obj = hashlib.md5()
			md5_obj.update(user_password.encode('utf-8'))
			md5_password = md5_obj.hexdigest()
			if _password == md5_password:
				print("密码认证成功")
				self.user_obj = self.accounts[user_name]
				# 用户家目录

				self.user_obj['home'] = os.path.join(setting.USER_HOME_DIR, user_name)

				return True
			else:
				print("密码错误")
				return False
		else:
			print("用户不存在")
			return False

	def _auth(self, data):
		"""
		下划线区分出与客户端交互的方法，处理用户认证
		:param data:
		:return:
		"""

		if self.authenticate(data.get('username'), data.get('password')):
			self.send_response(status_code=200)
		else:
			self.send_response(status_code=201)

	def send_response(self, status_code, *args, **kwargs):
		"""
		打包发送消息给客户端
		:param status_code:
		:param args:
		:param kwargs:
		:return:
		"""
		data = kwargs
		data['status_code'] = status_code
		data['status_msg'] = self.STATUS_CODE[status_code]
		data['fill'] = ''
		bytes_data = json.dumps(data).encode('utf-8')
		# 数据长度不够就补齐1024个长度
		if len(bytes_data) < self.MSG_SIZE:
			data['fill'] = data['fill'].zfill(self.MSG_SIZE - len(bytes_data))
			bytes_data = json.dumps(data).encode()

		self.request.send(bytes_data)

	def load_accounts(self):
		"""加载服务器端用户数据"""
		config_obj = configparser.ConfigParser()
		config_obj.read(setting.ACCOUNT_FILE)
		print(config_obj.sections())
		return config_obj

	def _get(self, data):
		"""下载数据 """
		print(data)
		file_name = data.get('filename')
		file_path = os.path.join(self.user_obj['home'], file_name)
		if os.path.isfile(file_path):
			file_size = os.stat(file_path).st_size
			# 发送文件大小数据
			self.send_response(301, file_size=file_size)
			print('已经发送文件信息')
			f = open(file_path, mode='rb')
			for line in f:
				self.request.send(line)
			else:
				print('文件发送完毕', file_path)
			f.close()
		else:

			self.send_response(300)

	def _ls(self, data):
		'''显示家目录路径文件,运用subprocess类库'''
		print(data)
		com_obj = subprocess.Popen('ls', shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
		stdout = com_obj.stdout.read()
		stderr = com_obj.stderr.read()
		print(stdout)
		print(stderr)
		com_result = stdout + stderr

		if not com_result:
			com_result = b'not folder'
		self.send_response(302, cmd_result_size=len(com_result))
		self.request.sendall(com_result)
